package by.dkusch.aircompany.dao.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.SingularAttribute;

import org.hibernate.jpa.criteria.OrderImpl;
import org.springframework.stereotype.Repository;

import by.dkusch.aircompany.dao.AirportDao;
import by.dkusch.aircompany.model.filter.FilterAirport;
import by.dkusch.aircompany.model.filter.base.FilterEntity;
import by.dkusch.aircompany.model.tables.Airport;
import by.dkusch.aircompany.model.tables.Airport_;
import by.dkusch.aircompany.model.tables.Country;
import by.dkusch.aircompany.model.tables.Country_;
import by.dkusch.aircompany.model.tables.Region;
import by.dkusch.aircompany.model.tables.Region_;
import by.dkusch.aircompany.model.tables.base.BaseEntity_;

@Repository
public class AirportDaoImpl extends AbstractDaoImpl<Long, Airport> implements AirportDao {

	public AirportDaoImpl() {
		super(Airport.class);
	}

	@Override
	public List<Airport> getAllItemsWithFilter(SingularAttribute<? super Airport, ?> attr, boolean ascending, int startRecord, int pageSize, FilterEntity<Long, ? super Airport> filter) {
		if (filter == null) {
			return getAllItems(attr, ascending, startRecord, pageSize);
		}

		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<Airport> criteria = cBuilder.createQuery(Airport.class);
		Root<Airport> fromAirport = criteria.from(Airport.class);

		@SuppressWarnings("unchecked")
		Join<Airport, Region> fromRegions = (Join<Airport, Region>) fromAirport.fetch(Airport_.region, JoinType.LEFT);
		@SuppressWarnings("unchecked")
		Join<Region, Country> fromCountry = (Join<Region, Country>) fromRegions.fetch(Region_.country, JoinType.LEFT);

		OrderImpl order = new OrderImpl(fromAirport.get(BaseEntity_.id), ascending);
		if (attr != null) {
			if (Region_.country.equals(attr)) {
				order = new OrderImpl(fromCountry.get(Country_.name), ascending);
			} else if (Airport_.region.equals(attr)) {
				order = new OrderImpl(fromRegions.get(Region_.code), ascending);
			} else {
				order = new OrderImpl(fromAirport.get(attr), ascending);
			}
		}
		;

		List<Predicate> conditions = new ArrayList<Predicate>();

		FilterAirport fc = (FilterAirport) filter;

		if (fc.getCode() != null) {
			conditions.add(cBuilder.equal(cBuilder.upper(fromAirport.get(Airport_.code)), fc.getCode().toUpperCase()));
		}

		if (fc.getName() != null) {
			conditions.add(cBuilder.like(cBuilder.upper(fromAirport.get(Airport_.name)), fc.getName().toUpperCase()));
		}

		if (fc.getContinent() != null) {
			conditions.add(cBuilder.equal(cBuilder.upper(fromAirport.get(Airport_.continent)), fc.getContinent().toUpperCase()));
		}

		if (fc.getRegionCode() != null) {
			conditions.add(cBuilder.equal(cBuilder.upper(fromRegions.get(Region_.code)), fc.getRegionCode().toUpperCase()));
		}

		if (fc.getType() != null) {
			conditions.add(cBuilder.equal(cBuilder.upper(fromAirport.get(Airport_.type)), fc.getType().toUpperCase()));
		}

		if (fc.getCountryCode() != null) {
			conditions.add(cBuilder.like(cBuilder.upper(fromCountry.get(Country_.name)), fc.getCountryCode().toUpperCase()));
		}

		TypedQuery<Airport> query = getEm().createQuery(criteria.select(fromAirport).where(cBuilder.and(conditions.toArray(new Predicate[] {}))).orderBy(order));

		if (startRecord >= 0) {
			query.setFirstResult(startRecord);
			query.setMaxResults(pageSize);
		}

		List<Airport> results = query.getResultList();
		return results;

	}

}
